#include "esp_log.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
/* BLE */
#include"ble_adv_scan.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "console/console.h"
#include "services/gap/ble_svc_gap.h"
#include "blecent.h"

#define GAP_ADTYPE_LOCAL_NAME_SHORT  0x08//设备缩写名
static const char *tag = "NimBLE_BLE_SCAN";
static int ble_gap_event(struct ble_gap_event *event, void *arg);
void ble_store_config_init(void);
QueueHandle_t adv_data_queue = NULL;

/* 初始化gap扫描 */
static void
ble_scan(void)
{
    uint8_t own_addr_type;
    struct ble_gap_disc_params disc_params;
    int rc;

    /* 找出广播时使用的地址（暂时没有隐私）*/
    rc = ble_hs_id_infer_auto(0, &own_addr_type);
    if (rc != 0) {
        MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
        return;
    }

    /* 过滤来自同一设备的重复广播  0不过滤  1过滤*/
    disc_params.filter_duplicates = 0;

   /* 执行被动扫描 不将后续扫描请求发送到广播  0主动扫描 1被动扫描*/
    disc_params.passive = 1;

    /* 其余参数使用默认值 */
    //扫描间隔 扫描窗口单位为0.625us
    disc_params.itvl = 320;
    disc_params.window = 160;
    disc_params.filter_policy = 0;
    disc_params.limited = 0;

    /* 启动扫描GAP流程 注册事件回调函数blecent_gap_event */
    rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
                      ble_gap_event, NULL);
    if (rc != 0) {
        MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
                    rc);
    }
}
/* 开启广播扫描 */
void ble_scan_on()
{
    ble_scan();
}
/* 关闭广播扫描 */
void ble_scan_off()
{
    int rc;

    rc = ble_gap_disc_cancel();
    if (rc != 0) {
        MODLOG_DFLT(DEBUG, "Failed to cancel scan; rc=%d\n", rc);
        return;
    }
}
/* 判断是否为想要扫描的广播 */
static void
ble_scan_if_interesting(struct ble_gap_disc_desc *disc)
{
    int rc;
    struct ble_hs_adv_fields fields;
    
    /* 解析广播PDU字段解析 */
    rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data);
    if (rc != 0) {
        ESP_LOGE(tag, "adv parse fields fail.");
        return;
    }

    print_adv_fields(&fields);
    /* 根据广播长度  广播数据第五个字节  判定  是否为想获取的广播 */
    if((disc->length_data == 24) && (disc->data[4] == GAP_ADTYPE_LOCAL_NAME_SHORT))
    {
        //把数据发送出去
        xQueueSend(adv_data_queue,fields.mfg_data,0);
    } 
}

/* nimble gap 事件回调函数 */
static int
ble_gap_event(struct ble_gap_event *event, void *arg)
{
    switch (event->type) {
    case BLE_GAP_EVENT_DISC:
        

        /* 判断是否为想要扫描的广播 */
        ble_scan_if_interesting(&event->disc);
        return 0;

    case BLE_GAP_EVENT_DISC_COMPLETE:
        ESP_LOGE(tag, "ble_gap_event:BLE_GAP_EVENT_DISC_COMPLETE");
        MODLOG_DFLT(INFO, "discovery complete; reason=%d\n",
                    event->disc_complete.reason);
        ESP_LOGI(tag, "BLE_GAP_EVENT_DISC_COMPLETE");
        return 0;
   
    default:
        return 0;
    }
}

static void
ble_on_reset(int reason)
{
    MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
}

static void
ble_on_sync(void)
{
    int rc;

    /* Make sure we have proper identity address set (public preferred) */
    /* 确保我们设置了正确的身份地址（公众首选） */
    rc = ble_hs_util_ensure_addr(0);
    assert(rc == 0);

#if !CONFIG_EXAMPLE_INIT_DEINIT_LOOP
    /* 开始扫描要连接的外围设备 */
    //ble_scan();
#endif
}

void ble_host_task(void *param)
{
    ESP_LOGI(tag, "BLE Host Task Started");
    /* This function will return only when nimble_port_stop() is executed */
    nimble_port_run();

    nimble_port_freertos_deinit();
}
void ble_scan_task_init()
{
    int rc;
    //ble协议栈初始化前必须先初始化NVS

    //创建消息队列
    adv_data_queue = xQueueCreate(5,5);
    if(adv_data_queue == NULL) ESP_LOGE(tag, "adv_data_queue create fail.");

    nimble_port_init();
    /* Configure the host. */
    ble_hs_cfg.reset_cb = ble_on_reset;//启动和重置   host controller  同步时回调
    ble_hs_cfg.sync_cb = ble_on_sync;//host 致命错误 reset时回调
    ble_hs_cfg.store_status_cb = ble_store_util_status_rr;//循环状态回调  如果记录空间不够会删除旧绑定并继续执行

    /* 初始化数据结构以跟踪连接的设备 */
    rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
    assert(rc == 0);

    /* 设置默认设备名 */
    rc = ble_svc_gap_device_name_set("nimble-blecent");
    assert(rc == 0);

    /* XXX Need to have template for store */
    ble_store_config_init();
    nimble_port_freertos_init(ble_host_task);  
}
void ble_scan_task_deinit()
{
    int rc;

    rc = nimble_port_stop;
    if(rc == 0)
    {
        nimble_port_deinit();
        rc = esp_nimble_deinit();
        if(rc != ESP_OK)
        {
            ESP_LOGE(tag, "esp_nimble_deinit fail,error:%d",rc);

            return;
        }
    }
    ESP_LOGI(tag, "BLE Host Task Close.");
}